<template>
  <el-select
    ref="selectRef"
    @focus="onFocus"
    class="remote-select"
    :loading="state.loading"
    :filterable="true"
    :remote="true"
    clearable
    remote-show-suffix
    :remote-method="onLogKeyword"
    v-model="state.value"
    @change="onChangeSelect"
    :multiple="multiple"
    :key="state.selectKey"
    @clear="onClear"
    @visible-change="onVisibleChange"
    v-loading="state.accidentBlur"
  >
    <el-option
      class="remote-select-option"
      v-for="item in state.options"
      :label="item[field]"
      :value="item[state.primaryKey].toString()"
      :key="item[state.primaryKey]"
    ></el-option>
    <el-pagination
      v-if="state.total"
      :currentPage="state.currentPage"
      :page-size="state.pageSize"
      class="select-pagination"
      layout="->, prev, next"
      :total="state.total"
      @current-change="onSelectCurrentPageChange"
    />
  </el-select>
</template>

<script setup lang="ts">
import { reactive, watch, onMounted, ref, nextTick } from "vue";
import { useMenu } from "@/store/backend/SysM/menu"; //远程下拉框参数获取
import { uuid } from "@/utils/random";
import { getSelectData } from "@/utils/common";
import type { ElSelect } from "element-plus";

const menu = useMenu();
const selectRef = ref<InstanceType<typeof ElSelect> | undefined>();
type valType = string | number | string[] | number[];

interface Props {
  pk?: string;
  field?: string;
  params?: anyObj;
  multiple?: boolean;
  remoteUrl: string;
  modelValue: valType;
}
const props = withDefaults(defineProps<Props>(), {
  pk: "menuId",
  field: "menuName",
  params: () => {
    return {};
  },
  remoteUrl: "",
  modelValue: "",
  multiple: false,
});

const state: {
  // 主表字段名(不带表别名)
  primaryKey: string;
  options: anyObj[];
  loading: boolean;
  total: number;
  currentPage: number;
  pageSize: number;
  params: anyObj;
  keyword: string;
  value: valType;
  selectKey: string;
  initializeData: boolean;
  accidentBlur: boolean;
} = reactive({
  primaryKey: props.pk,
  options: [],
  loading: false,
  total: 0,
  currentPage: 1,
  pageSize: 10,
  params: props.params,
  keyword: "",
  value: props.modelValue,
  selectKey: uuid(),
  initializeData: false,
  accidentBlur: false,
});

const emits = defineEmits<{
  (e: "update:modelValue", value: valType): void;
}>();

const onChangeSelect = (val: valType) => {
  emits("update:modelValue", val);
};

const onVisibleChange = (val: boolean) => {
  // 保持面板状态和焦点状态一致
  if (!val) {
    nextTick(() => {
      selectRef.value?.blur();
    });
  }
};

const onFocus = () => {
  if (props.multiple && selectRef.value?.query != state.keyword) {
    state.keyword = selectRef.value!.query;
    state.initializeData = false;
    // el-select 自动清理搜索词会产生意外的脱焦
    state.accidentBlur = true;
  }
  if (!state.initializeData) {
    getData();
  }
};

const onClear = () => {
  state.keyword = "";
  state.initializeData = false;
};

const onLogKeyword = (q: string) => {
  state.keyword = q;
  getData();
};

const getData = (initValue: valType = "") => {
  state.loading = true;
  state.params.page = state.currentPage;
  state.params.initKey = props.pk;
  state.params.initValue = initValue;
  getSelectData(props.remoteUrl, state.keyword, state.params)
    .then((res: any) => {
      let initializeData = true;
      let opts = res.data ? res.data : res.data.list;
      // state.options = handleTree(opts, "menuId", "", "");
      state.options = opts;
      state.total = res.data.total ?? 0;
      if (initValue) {
        // 重新渲染组件,确保在赋值前,opts已加载到-兼容 modelValue 更新
        state.selectKey = uuid();
        initializeData = false;
      }
      state.loading = false;
      state.initializeData = initializeData;
      if (state.accidentBlur) {
        nextTick(() => {
          selectRef.value?.focus();
          state.accidentBlur = false;
        });
      }
    })
    .catch(() => {
      state.loading = false;
    });
};

const onSelectCurrentPageChange = (val: number) => {
  state.currentPage = val;
  getData();
};

const initDefaultValue = () => {
  if (state.value) {
    // number[]转string[]确保默认值能够选中
    if (typeof state.value === "object") {
      for (const key in state.value as string[]) {
        state.value[key] = state.value[key].toString();
      }
    } else if (typeof state.value === "number") {
      state.value = state.value.toString();
    }
    getData(state.value);
  }
};

onMounted(() => {
  if (props.pk.indexOf(".") > 0) {
    let pk = props.pk.split(".");
    state.primaryKey = pk[1] ? pk[1] : pk[0];
  }
  initDefaultValue();
});

watch(
  () => props.modelValue,
  (newVal) => {
    if (state.value.toString() != newVal.toString()) {
      state.value = newVal;
      initDefaultValue();
    }
  }
);
</script>

<style scoped lang="scss">
.remote-select {
  width: 100%;
}

.remote-select-option {
  white-space: pre;
}
</style>
